Android Surface的理解和应用

您所在的位置:网站首页 surface pro30fd347鏓a7win11417 Android Surface的理解和应用

Android Surface的理解和应用

2023-03-28 19:10| 来源: 网络整理| 查看: 265

近两年一直在做Android直播相关业务,很多是从0开始接触,比如摄像头采集,美颜处理,像素提取,视频播放等场景,其中比较绕也容易迷的是Surface,结合自己的理解加以总结;

对Surface体系的理解:

image.png

这张图概况了Android系统从图像采集输入到渲染到屏幕的大致流程,我挑选其中的Sruface作为切入点来分析;Suraface也是我们应用层能接触到的比较核心的API了;

简述 Surface能对接很多API,包括不限于SurfaceView、SurfaceTexture、SurfaceFlinger、MediaCodec、ImageReader、Camera、Player、EGL,不要懵逼,它本质是一个图像生产者(Image stream Producer);

image.png

还不明白?通俗易懂的说,生产方是创造数据,你手里有一批图像流产出,就可以考虑吐给Surface,想一想,Palyer和Camera是不是干这个事的;

谁来管理这个生产消费关系的?这是一个需要深入源码探究的话题,但至少得认识到有一个BufferQueue来管理生产消费队列;还有一点很重要,这个BufferQueue可以跨进程的,比如SurfaceFlinger场景,至于这坨内存如何跨进程传输的,可以研究一下Binder、匿名共享内存和ion驱动; image.png 生产方 生产者拿到Surface如何往里灌数据,一般有三种方式: 通过Surface拿到Canvas,CanvasAPI再简单不过了 通过Surface创建EGL,我用openGLES自己搞,可还行 我已经有RGB像素内容,直接干就完了

当然这三种都有对应的业务场景,比如基于OpenGLES的游戏和美颜相机就是第二种,比如使用软渲染的播放器,就是第三种情况;

opengles作为生成方,如何与Surface关联,其实是基于EGL,EGL是衔接gles和本地窗口的桥梁;EGL工作流程如下

image.png

简单一点理解:创建EGL环境需要绑定一个渲染表面,这个载体可以是系统窗口,也可以是内存的缓冲区,我们通过这种手段把Surface和EGL进行某种绑定,等gles绘制流程走完再调用swapBuffer后,数据就会写到绑定的那块Surface上;

Surface生产方更常见的ViewRoot之Surface和SurfaceFlinger,这一块基本上成了面试必问知识点了,一张图概况;

image.png 注意硬件加速下绘制流程会有所区别,但是和SurfaceFlinger的交互流程还是一样; 除此之外,还需要明白SurfacView是特殊的View,它拥有的Surface内容可以直接映射到SurfaceFlinger方的layer,等于是和ViewRoot对应的Surface是平级的;

消费方

Surface体系消费方有哪些?这个在开发过程中,往往容易被忽视,实际上你可能已经有所使用但没有察觉,因为系统已经把生成方都封装好了;

换一种说法,当你在应用层能拿到Surface对象时,其实背后已经对应了一个消费方了,大部分是这种情况;

假设你从SurfaceView获取Surface,那么消费方就是SurfaceFlinger; 假设你从TextureView获取Surface,那么消费方就是SurfaceTexture; 假设你从MediaCodec获取Surface,那么消费方就是MediaCodec;

每一个消费方背后,都拥有一套BufferQueue,消费方拿到图像数据,各自干不同的事情;

image.png

SurfaceTexture作为消费方,同时也是图像流处理过程比较常见的API,这玩意到底是干啥的?

image.png

一言以蔽之,这家伙是把Surface数据流转成外部纹理,可以给gles使用的纹理;

划重点:TextureView内部也是基于SurfaceTexture,把数据转成纹理,再绑定到硬件加速View渲染节点上,但它依然是NodeTree的一个节点,且参与整个硬件加速NodeTree的图像合成,所以很容易解释TextureView为什么能像普通View一样拥有层级,没有挖洞问题,同时也很容易理解为什么TextureView会比SurfaceView慢几个同步周期;

应用场景总结

端上图像采集,一般有两种业务场景,摄像头和录屏,这一步要明白你是消费方,你拿到数据干什么;想直接拿yuv/rgb裸数据,可以考虑用ImageReader接收;如果需要图像二次处理,比如美颜和水印,或者剪裁等,建议走GPU(opengles),由于GLES接受的是纹理类型,如何把裸数据转成纹理,两种方式:1、yuv/rgb通过gl转纹理 2、通过SurfaceTexture转,一般会用方式2;

GPU像素拷贝,这种场景也比较常见,如何获取GLES渲染后的数据,一般有三种方式,1、通过glReadPixels直接或者,2、通过ImagerReader获取,3、通过EGLImageKHR+HardwareBuffer获取,一般方式1需要配合pbo效率才好,纯java建议使用方式2,native层可以使用方式3

渲染到View,这种往往是采集预览和播放器类似场景,很普通的场景但依然可以玩出花样,比如在不改造播放器的情况下,把一路视频流拆分不同区域,渲染到两个SurfaceView上,想想怎么搞,这种情况就可以结合SurfaceTexture和GLES方向思考一下。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3